﻿/** FORM1 CLASS
 * Author: Preeti Francis
 * User ID : pxfranci@scotty.cs.wichita.edu
 * WSU ID: S578F746
 * Course: CS771 
 * Sem: S2014
 * 
 * Description of Class : Form1 class is the User Interface class.
 * It contains methods to bind data to the controls and display the solution. 
 * **/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using _8PiecePuzzle.ProgramLogic;
using _8PiecePuzzle.DataStructures;

namespace _8PiecePuzzle
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public int[][] InitialState { get; set; }
        public int[][] GoalState { get; set; }

        //Clears text boxes when reset
        private void ClearTextBoxes()
        {
            txtMessage.Text = string.Empty;
            txt_2_2.Text = string.Empty;
            txt_2_1.Text = string.Empty;
            txt_2_0.Text = string.Empty;
            txt_1_2.Text = string.Empty;
            txt_1_1.Text = string.Empty;
            txt_1_0.Text = string.Empty;
            txt_0_2.Text = string.Empty;
            txt_0_1.Text = string.Empty;
            txt_0_0.Text = string.Empty;
            lblSteps.Text = string.Empty;
        }

        //Enables or disables the controls based on bool passed
        private void EnableDisable(bool enable)
        {
            gs_txt_2_2.Enabled =
            gs_txt_2_1.Enabled =
            gs_txt_2_0.Enabled =
            gs_txt_1_2.Enabled =
            gs_txt_1_1.Enabled =
            gs_txt_1_0.Enabled =
            gs_txt_0_2.Enabled =
            gs_txt_0_1.Enabled =
            gs_txt_0_0.Enabled =
            txt_2_2.Enabled =
            txt_2_1.Enabled =
            txt_2_0.Enabled =
            txt_1_2.Enabled =
            txt_1_1.Enabled =
            txt_1_0.Enabled =
            txt_0_2.Enabled =
            txt_0_1.Enabled =
            txt_0_0.Enabled =
            btnSolve.Enabled = enable;
            btnRestart.Enabled = !enable;
        }

        //Button click event for solve
        private void btnSolve_Click(object sender, EventArgs e)
        {
            EnableDisable(false);
            //Validate textboxes else return a message
            if (!AreEntriesValid())
            {
                return;
            }
            //Add values to int[][] and get Goal and Initial States
            InitialState = GetInitialArray();
    
            GoalState = GetGoalState();
            
            //Call A star algorithm and get all the states.
            AStarProgramLogic aStarAlgorithm = new AStarProgramLogic(GoalState, InitialState);
            Node goalNode = aStarAlgorithm.GetGoal();

            /* Use goal state and go backwards to populate the grid 
             * and keep adding it to the string builder and then 
             * generate output */
            ShowOutput(goalNode);
        }

        //Displays the output in the message text box
        private void ShowOutput(Node goalNode)
        {
            if (goalNode == null)
            {
                txtMessage.Text = "Either the solution does not exist or will not be available within polynomial time for this configuration. Please try again with a different set of values.";
                
                return;
            }

            lblSteps.Text = goalNode.PathCost.ToString();

            StringBuilder outputMessage = new StringBuilder();

            do
            {
                string stringBorder = "\r\n***************************************************\r\n";
                string pathCostValue = string.Format("Step # {0}:",goalNode.PathCost.ToString());
                string value = string.Format("{0} {1} {2}\r\n{3} {4} {5}\r\n{6} {7} {8}\r\n",
                    goalNode.State[0][0].ToString(),
                    goalNode.State[0][1].ToString(),
                    goalNode.State[0][2].ToString(),
                    goalNode.State[1][0].ToString(),
                    goalNode.State[1][1].ToString(),
                    goalNode.State[1][2].ToString(),
                    goalNode.State[2][0].ToString(),
                    goalNode.State[2][1].ToString(),
                    goalNode.State[2][2].ToString());

                outputMessage.Insert(0,string.Format("{0}{1}{2}{3}",stringBorder,pathCostValue,stringBorder,value));
                                
                goalNode = goalNode.Parent;

            } while ((goalNode!=null));

            txtMessage.Text = outputMessage.ToString();
        }

        //Gets goal state entered by the user
        private int[][] GetGoalState()
        {
            int[][] goalState = new int[3][]
            {          
                new int[3],
                new int[3],
                new int[3]
            };

            goalState[0][0] = System.Convert.ToInt32(gs_txt_0_0.Text);
            goalState[0][1] = System.Convert.ToInt32(gs_txt_0_1.Text);
            goalState[0][2] = System.Convert.ToInt32(gs_txt_0_2.Text);

            goalState[1][0] = System.Convert.ToInt32(gs_txt_1_0.Text);
            goalState[1][1] = System.Convert.ToInt32(gs_txt_1_1.Text);
            goalState[1][2] = System.Convert.ToInt32(gs_txt_1_2.Text);

            goalState[2][0] = System.Convert.ToInt32(gs_txt_2_0.Text);
            goalState[2][1] = System.Convert.ToInt32(gs_txt_2_1.Text);
            goalState[2][2] = System.Convert.ToInt32(gs_txt_2_2.Text);

            return goalState;
        }

        //Gets the initial state entered by the user
        private int[][] GetInitialArray()
        {
            int[][] initialState = new int[3][]
            {          
                new int[3],
                new int[3],
                new int[3]
            };
            
            initialState[0][0] = System.Convert.ToInt32(txt_0_0.Text);
            initialState[0][1] = System.Convert.ToInt32(txt_0_1.Text);
            initialState[0][2] = System.Convert.ToInt32(txt_0_2.Text);

            initialState[1][0] = System.Convert.ToInt32(txt_1_0.Text);
            initialState[1][1] = System.Convert.ToInt32(txt_1_1.Text);
            initialState[1][2] = System.Convert.ToInt32(txt_1_2.Text);

            initialState[2][0] = System.Convert.ToInt32(txt_2_0.Text);
            initialState[2][1] = System.Convert.ToInt32(txt_2_1.Text);
            initialState[2][2] = System.Convert.ToInt32(txt_2_2.Text);

            return initialState;
        }

        //Validates entries
        private bool AreEntriesValid()
        {
            int i;
            //Check if all values are entered
            if (!((int.TryParse(txt_0_0.Text, out i) && (i > 0 || i < 8)) && (int.TryParse(txt_0_1.Text, out i) && (i > 0 || i < 8)) && (int.TryParse(txt_0_2.Text, out i) && (i > 0 || i < 8)) &&
                (int.TryParse(txt_1_0.Text, out i) && (i > 0 || i < 8)) && (int.TryParse(txt_1_1.Text, out i) && (i > 0 || i < 8)) && (int.TryParse(txt_1_2.Text, out i) && (i > 0 || i < 8)) &&
                (int.TryParse(txt_2_0.Text, out i) && (i > 0 || i < 8)) && (int.TryParse(txt_2_1.Text, out i) && (i > 0 || i < 8)) && (int.TryParse(txt_2_2.Text, out i) && (i > 0 || i < 8))))
            {
                MessageBox.Show("Please enter valid integers in the range 0 to 8!");
                return false;
            }
            //check for 0 to 8
            if (!((int.TryParse(gs_txt_0_0.Text, out i) && (i > 0 || i < 8)) && (int.TryParse(gs_txt_0_1.Text, out i) && (i > 0 || i < 8)) && (int.TryParse(gs_txt_0_2.Text, out i) && (i > 0 || i < 8)) &&
               (int.TryParse(gs_txt_1_0.Text, out i) && (i > 0 || i < 8)) && (int.TryParse(gs_txt_1_1.Text, out i) && (i > 0 || i < 8)) && (int.TryParse(gs_txt_1_2.Text, out i) && (i > 0 || i < 8)) &&
               (int.TryParse(gs_txt_2_0.Text, out i) && (i > 0 || i < 8)) && (int.TryParse(gs_txt_2_1.Text, out i) && (i > 0 || i < 8)) && (int.TryParse(gs_txt_2_2.Text, out i) && (i > 0 || i < 8))))
            {
                MessageBox.Show("Please enter valid integers in the range 0 to 8!");
                return false;
            }
            return true;
        }

        //Resets to start a new game
        private void btnRestart_Click(object sender, EventArgs e)
        {
            ClearTextBoxes();
            EnableDisable(true);
        }
    }
}
